﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Xml.Linq;
using AzukiMap.Layer;
using AzukiMap.MapSource;
using AzukiMap.Tools;
using AzukiMap.Tools.Logger;
using GeoAPI.CoordinateSystems;
using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Geometries;
using ProjNet.CoordinateSystems.Transformations;
using Geometry = GisSharpBlog.NetTopologySuite.Geometries.Geometry;
using Point = System.Windows.Point;

namespace AzukiMap.Map
{
    public delegate void MapExtentChangedHandler(object sender, MapExtentChangedArgs e);

    public delegate void MapScaleChangedHandler(object sender, MapScaleChangedArgs e);

    public delegate void MapProjectionChangedHandler(object sender, MapProjectionChangedArgs e);

    public delegate void MapRotationChangedHandler(object sender, MapRotationChangedArgs e);

    public delegate void MouseMovedHandler(object sender, MouseMovedArgs e);

    public delegate void LayerAddedHandler(object sender, LayerAddedArgs e);

    public delegate void MouseClickedHandler(object sender, MouseClickedArgs e);

    public delegate void MouseRangeBoxFixedHandler(object sender, MouseRangeBoxFixedArgs e);

    public delegate void MouseFeatureEditFixedHandler(object sender, MouseFeatureEditFixedArgs e);

    public class MapControl
    {
        // for auto move

        public IPolygon CurrentExtent
        {
            get { return MapCoordinate.CurrentExtent; }
        }

        public IPolygon PreviousExtent
        {
            get { return MapCoordinate.LastExtent; }
        }

        public int Srid
        {
            get { return MapCoordinate.Srid; }
            set
            {
                if ( MapCoordinate.Srid == value)
                {
                    return;
                }
                if ( MapCoordinate.Srid > 0 )
                {
                    int orgSrid = MapCoordinate.Srid;
                    MapCoordinate.Srid = value;
                    ChangeProjectionBySrid(orgSrid);
                } 
                else
                {
                    MapCoordinate.Srid = value;
                }

            }
        }

        public double Tolerance
        {
            get { throw new NotImplementedException(); }
        }

        public bool FlipY
        {
            get { return MapCoordinate.FlipY; }
        }

        public double ScreenScale
        {
            get { return MapCoordinate.ScreenScale; }
        }

        public double GeoScale
        {
            get { return MapCoordinate.GeoScale; }
        }

        public double Angle
        {
            get { return MapCoordinate.Angle; }
        }

        public double MinScale
        {
            get { return _minScale; }
            set
            {
                if (value < 0)
                {
                    Logger.Error("Layer.minScale: MinScale should be >= 0.");
                    throw new ArgumentException("MinScale should be >= 0.", "MinScale");
                }
                if (_maxScale != 0 && _maxScale < value)
                {
                    Logger.Error("Layer.minScale: MinScale should be less than MinScale.");
                    throw new ArgumentException("MinScale should be less than MinScale.", "MinScale");
                }
                _minScale = value;
                _mouseControl.MinScale = value;
                MapCoordinate.MinScale = value;
            }
        }

        public double MaxScale
        {
            get { return _maxScale; }
            set
            {
                if (value <= 0)
                {
                    Logger.Error("Layer.MaxScale: MaxScale should be > 0.");
                    throw new ArgumentException("MaxScale should be > 0.", "MaxScale");
                }
                if (_minScale != 0 && _minScale > value)
                {
                    Logger.Error("Layer.MaxScale: MaxScale should be greater than MinScale.");
                    throw new ArgumentException("MaxScale should be greater than MinScale.", "MinScale");
                }
                _maxScale = value;
                _mouseControl.MaxScale = value;
                MapCoordinate.MaxScale = value;
            }
        }

        public void AutoMoveStart(double lon, double lat)
        {
            if (_mouseControl != null)
            {
                IPoint src = MapCoordinate.GetPixPointFromGeo(CurrentExtent.Centroid);
                IPoint dst = MapCoordinate.GetPixPointFromGeo(GeometryUtil.Default.CreatePoint(lon, lat));
                _mouseControl.AutoMoveStart(new Point(src.X, src.Y), new Point(dst.X, dst.Y));
            }
        }

        public XElement ToXml()
        {
            var xmlCommon = new XmlCommon();
            var mapXml = new XElement("aml",
                                      xmlCommon.CreateAttr("Srid", Srid),
                                      xmlCommon.CreateAttr("FlipY", FlipY),
                                      xmlCommon.CreateAttr("MinScale", MinScale),
                                      xmlCommon.CreateAttr("MaxScale", MaxScale),
                                      xmlCommon.GeometryToXml("CurrentExtent", CurrentExtent),
                                      LayerManager.ToXml()
                );
            return mapXml;
        }

        public void Parse(XDocument aml)
        {
            XElement amlRoot = aml.Element("aml");
            var xmlCommon = new XmlCommon();
            var layerXmlParser = new LayerXmlParser();

            Srid = xmlCommon.GetIntAttr(amlRoot, "Srid");
            MapCoordinate.FlipY = xmlCommon.GetBoolAttr(amlRoot, "FlipY");
            MinScale = xmlCommon.GetDoubleAttr(amlRoot, "MinScale");
            MaxScale = xmlCommon.GetDoubleAttr(amlRoot, "MaxScale");
            var extent = (IPolygon) xmlCommon.GetGeomElement(amlRoot, "CurrentExtent");
            MoveToExtents(extent);
            if (amlRoot != null)
            {
                XElement layers = amlRoot.Element("Layers");
                if (layers != null)
                {
                    foreach (XElement element in layers.Elements())
                    {
                        MapLayer layer = layerXmlParser.Parse(element);
                        if (layer != null)
                            AddLayer(layer);
                    }
                }
            }
        }

        public void SetLayerDrawable(bool drawable)
        {
            LayerManager.SetLayerDrawable(drawable);
        }


        public void SetRectFeature(IGeometry selectedArea)
        {
            SetEditGeometry(selectedArea);

            EditVectorLayer layer = LayerManager.EditLayer;
            EditVectorSource source = LayerManager.EditSource;

            source.EditPoint = null;
            source.SetWorkFeature();
            layer.EditVectorMode = EditVectorMode.NoEdit;
            layer.Draw();

            var args = new MouseFeatureEditFixedArgs {Geometry = source.WorkGeometry};
            OnMouseFeatureEditFixed(args);
        }

        #region events 

        public bool MouseEnabled
        {
            set { _mouseControl.Enabled = value; }
        }

        public event MapExtentChangedHandler MapExtentChanged;
        public event MapScaleChangedHandler MapScaleChanged;
        public event MapProjectionChangedHandler MapProjectionChanged;
        public event MapRotationChangedHandler MapRotationChanged;
        public event MouseMovedHandler MouseMoved;
        public event LayerAddedHandler LayerAdded;

        public event MouseClickedHandler MouseClicked;
        public event MouseRangeBoxFixedHandler MouseRangeBoxFixed;
        public event MouseFeatureEditFixedHandler MouseFeatureEditFixed;

        protected virtual void OnMapExtentChanged(MapExtentChangedArgs e)
        {
            if (MapExtentChanged != null)
            {
                MapExtentChanged(this, e);
            }
        }

        protected virtual void OnMapScaleChanged(MapScaleChangedArgs e)
        {
            if (MapScaleChanged != null)
            {
                MapScaleChanged(this, e);
            }
            foreach (ILayer layer in LayerManager.Layers)
            {
                layer.MapScaleChanged(this, e);
            }
        }

        protected virtual void OnMapProjectionChanged(MapProjectionChangedArgs e)
        {
            if (MapProjectionChanged != null)
            {
                MapProjectionChanged(this, e);
            }
        }

        protected virtual void OnMapRotationChanged(MapRotationChangedArgs e)
        {
            if (MapRotationChanged != null)
            {
                MapRotationChanged(this, e);
            }
        }

        protected virtual void OnMouseMoved(MouseMovedArgs e)
        {
            if (MouseMoved != null)
            {
                MouseMoved(this, e);
            }
        }

        protected virtual void OnMouseClicked(MouseClickedArgs e)
        {
            if (MouseClicked != null)
            {
                MouseClicked(this, e);
            }
        }

        protected virtual void OnMouseRangeBoxFixed(MouseRangeBoxFixedArgs e)
        {
            if (MouseRangeBoxFixed != null)
            {
                MouseRangeBoxFixed(this, e);
            }
            _hasArea = true;
            // TODO:
            //RestoreMapMouseMode();
        }

        protected virtual void OnMouseFeatureEditFixed(MouseFeatureEditFixedArgs e)
        {
            if (MouseFeatureEditFixed != null)
            {
                MouseFeatureEditFixed(this, e);
            }
            _hasArea = true;

            // TODO: 
            //RestoreMapMouseMode();
        }

        protected virtual void OnLayerAdded(LayerAddedArgs e)
        {
            if (LayerAdded != null)
            {
                LayerAdded(this, e);
            }
        }

        #endregion

        # region fields

        private readonly LabelLayer _labelLayer;
        private readonly MapMouseControl _mouseControl;
        private Rect _clipRect;
        private StackPanel _copyrightStack;
        private bool _hasArea;
        private double _maxScale = double.MaxValue;
        private double _minScale;

        # endregion

        # region properties

        public Canvas RootCanvas { get; private set; }

        public MapCoordinate MapCoordinate { get; private set; }

        public LayerManager LayerManager { get; private set; }
       
        public ObservableCollection<ILayer> Layers
        {
            get
            {
                return LayerManager.Layers;
            }
        }

        private bool _is180Connected;

        public bool Is180Connected
        {
            get { return _is180Connected; }
            set
            {
                _is180Connected = value;
                if ( MapCoordinate != null )
                {
                    MapCoordinate.Is180Connected = value; 
                }
            }
        }

        private double _eastEnd;

        /// <summary>
        /// Max X for connecting the east + west canvases
        /// </summary>
        public double EastEnd
        {
            get { return _eastEnd; }
            set
            {
                _eastEnd = value;
                if ( MapCoordinate != null )
                {
                    MapCoordinate.EastEnd = value;
                }
            }
        }

        private double _westEnd;

        /// <summary>
        /// Min X for connection the east + west canvases.
        /// </summary>
        public double WestEnd
        {
            get { return _westEnd; }
            set
            {
                _westEnd = value;
                if ( MapCoordinate != null )
                {
                    MapCoordinate.WestEnd = value;
                }
            }
        }

        # endregion

        # region constructor

        /*
        public MapControl(Canvas rootCanvas, int srid) : this(rootCanvas)
        {
            this.Srid = srid;
            LayerManager.InitSpecialLayers(MapCoordinate);
        }
         * */

        // previous mouse mode
        private MapMouseMode _oldMapMouseMode = MapMouseMode.None;

        public MapControl(Canvas rootCanvas)
        {
            WestEnd = double.NegativeInfinity;
            EastEnd = double.PositiveInfinity;
            Logger.Debug("MapControl.MapControl: Init starts.");

            _clipRect = new Rect();
            RootCanvas = PrepereRootCanvas(rootCanvas);
            _mouseControl = new MapMouseControl(RootCanvas);
            Canvas layerContainer = _mouseControl.LayerContainer;
            LayerManager = new LayerManager(layerContainer);

            RootCanvas.SizeChanged += RootCanvasSizeChanged;
            _mouseControl.LayerContainerMoved += MouseControlContainerMoved;
            _mouseControl.ScreenScaleChanged += MouseControlScreenScaleChanged;
            _mouseControl.MouseMovedOnScreen += MouseControlMouseMoved;

            _mouseControl.MouseClickedOnScreen += mouseControl_MouseClickedOnScreen;
            _mouseControl.MouseRangeBox += _mouseControl_MouseRangeBox;
            _mouseControl.MouseFeatureEdit += _mouseControl_MouseFeatureEdit;
            _mouseControl.MouseFeatureDrag += _mouseControl_MouseFeatureDrag;

            MapCoordinate = new MapCoordinate();

            _labelLayer = new LabelLayer(layerContainer, MapCoordinate);
            CreateCopyrightStack();

            // by Shimohana TODO rootCanvas 
            LayerManager.InitSpecialLayers(MapCoordinate, _mouseControl, rootCanvas);

            Is180Connected = false;
            WestEnd = -180;
            EastEnd = 180;

            Logger.Debug("MapControl.MapControl: Init finshed.");
        }

        public MapMouseMode MapMouseMode
        {
            get { return _mouseControl.MapMouseMode; }
            set
            {
                if (_mouseControl.MapMouseMode == value)
                {
                    return;
                }

                // Save mode. for back from the edit mode.
                _oldMapMouseMode = _mouseControl.MapMouseMode;

                _mouseControl.MapMouseMode = value;

                switch (_mouseControl.MapMouseMode)
                {
                    case MapMouseMode.DragMove:
                        LayerManager.EditLayer.EditVectorMode = EditVectorMode.NoEdit;
                        LayerManager.EditSource.EditVectorType = EditVectorType.Node;
                        LayerManager.EditSource.Clear();
                        LayerManager.EditLayer.Draw();
                        break;
                    case MapMouseMode.CreatePolygon:
                        //LayerManager.EditLayer.EditVectorMode = EditVectorMode.Create;
                        LayerManager.EditLayer.EditVectorMode = EditVectorMode.NoEdit;
                        LayerManager.EditSource.EditVectorType = EditVectorType.Polygon;
                        LayerManager.EditSource.Clear();
                        LayerManager.EditLayer.Draw();
                        break;
                    case MapMouseMode.CreateRectangle:
                        //LayerManager.EditLayer.EditVectorMode = EditVectorMode.Create;
                        LayerManager.EditLayer.EditVectorMode = EditVectorMode.NoEdit;
                        LayerManager.EditSource.EditVectorType = EditVectorType.Rectangle;
                        LayerManager.EditSource.Clear();
                        LayerManager.EditLayer.Draw();
                        break;
                    case MapMouseMode.CreatePoint:
                        //LayerManager.EditLayer.EditVectorMode = EditVectorMode.Create;
                        LayerManager.EditLayer.EditVectorMode = EditVectorMode.NoEdit;
                        LayerManager.EditSource.EditVectorType = EditVectorType.Node;
                        LayerManager.EditSource.Clear();
                        LayerManager.EditLayer.Draw();
                        break;
                    case MapMouseMode.EditPolygon:
                        LayerManager.EditLayer.EditVectorMode = EditVectorMode.Edit;
                        LayerManager.EditSource.EditVectorType = EditVectorType.Polygon;
                        LayerManager.EditLayer.Draw();
                        break;
                }
            }
        }

        private void RestoreMapMouseMode()
        {
            MapMouseMode = _oldMapMouseMode;
        }

        /// <summary>
        /// Set geometry for edit.
        /// </summary>
        /// <param name="geom"></param>
        public void SetEditGeometry(IGeometry geom)
        {
            LayerManager.EditSource.SetGeometry(geom);
            LayerManager.EditLayer.Draw();
            OnMouseFeatureEditFixed(new MouseFeatureEditFixedArgs(){Geometry = geom});
        }

        /// <summary>
        /// Clear geometry for edit.
        /// </summary>
        public void ClearEditGeometry()
        {
            LayerManager.EditSource.Clear();
            LayerManager.EditLayer.Draw();
        }

        /// <summary>
        /// Get geometry for edit.
        /// </summary>
        /// <returns></returns>
        public IGeometry GetEditGeometry()
        {
            return LayerManager.EditSource.GetGeometry();
        }

        # endregion

        # region canvas settings

        private Canvas PrepereRootCanvas(Canvas _rootCanvas)
        {
            Logger.Debug("MapControl.PrepereRootCanvas");

            // if the background is null mouse events on the canvas are not fired.
            if (_rootCanvas.Background == null)
            {
                _rootCanvas.Background = new SolidColorBrush(Colors.White);
            }
            // set the clip in the _rootCanvas
            if (_rootCanvas.Clip == null)
            {
                //SetClipOnRootCanvas(_rootCanvas.ActualWidth, _rootCanvas.ActualHeight);
            }

            //_rootCanvas.LayoutUpdated += new EventHandler(rootCanvas_LayoutUpdated);
            _rootCanvas.SizeChanged += RootCanvasSizeChanged;
            //_rootCanvas.LayoutUpdated += new EventHandler(SetMapContext);
            _rootCanvas.UpdateLayout();
            return _rootCanvas;
        }


        private void SetClipOnRootCanvas(double width, double height)
        {
            Logger.Debug(
                "MapControl.SetClipOnRootCanvas:"
                + " width = " + width
                + " height= " + height
                );

            if (width == 0 && height == 0)
            {
                return;
            }
            _clipRect.X = 0;
            _clipRect.Y = 0;
            _clipRect.Width = width;
            _clipRect.Height = height;
            var clipGeom = new RectangleGeometry();
            clipGeom.Rect = _clipRect;
            RootCanvas.SetValue(UIElement.ClipProperty, clipGeom);
        }

        # endregion

        #region MapControl

        public Point LastClickPoint
        {
            // TODO timing ...
            get { return _mouseControl.LastClickPoint; }
        }

        public double GetScreenWidth()
        {
            return RootCanvas.ActualWidth;
        }

        public double GetScreenHeight()
        {
            return RootCanvas.ActualHeight;
        }

        public IPolygon GetExtents()
        {
            return MapCoordinate.CurrentExtent;
        }

        public void MoveTo(double lon, double lat)
        {
            Logger.Debug(
                "MapControl.MoveTo(2):"
                + " lon = " + lon
                + " lat = " + lat
                );

            MapCoordinate.MoveTo(lon, lat);
            LayerManager.RemoveAllDrawings();
            _labelLayer.Clear();
            LayerManager.DrawAll();
            FireMapExtentChanged(MapCoordinate.CurrentExtent);
        }

        public void MoveTo(double lon, double lat, double geoScale)
        {
            Logger.Debug(
                "MapControl.MoveTo(3):"
                + " lon = " + lon
                + " lat = " + lat
                + " newScale = " + geoScale
                );

            MapCoordinate.MoveToScale(lon, lat, geoScale);
            FireMapExtentChanged(MapCoordinate.CurrentExtent);
            FireMapScaleChanaged(MapCoordinate.GeoScale, MapCoordinate.ScreenScale);
        }

        public void MoveToExtents(double minLon, double minLat, double maxLon, double maxLat)
        {
            Logger.Debug(
                "MapControl.MoveToExtent(3):"
                + " minLon = " + minLon
                + " minLat = " + minLat
                + " maxLon = " + maxLon
                + " maxLat = " + maxLat
                );

            MapCoordinate.MoveToExtent(minLon, minLat, maxLon, maxLat);

            FireMapExtentChanged(MapCoordinate.CurrentExtent);
            FireMapScaleChanaged(MapCoordinate.GeoScale, MapCoordinate.ScreenScale);
        }

        private void MoveToExtents(IPolygon extent)
        {
            MapCoordinate.MoveToExtent(extent);
            FireMapExtentChanged(MapCoordinate.CurrentExtent);
            FireMapScaleChanaged(MapCoordinate.GeoScale, MapCoordinate.ScreenScale);
        }

        public void SetScale(double newScale)
        {
            if (IsNearScale(newScale))
                return;

            Logger.Debug(
                "MapControl.SetScale():"
                + " newScale = " + newScale
                );
            if (newScale < _minScale)
            {
                newScale = _minScale;
            }
            if (_maxScale < newScale)
            {
                newScale = _maxScale;
            }

            //MapCoordinate.ScreenScale = newScale;
            MapCoordinate.ZoomByScale(newScale);

            IPolygon extent = MapCoordinate.CurrentExtent;
            FireMapExtentChanged(extent);
            FireMapScaleChanaged(MapCoordinate.GeoScale, MapCoordinate.ScreenScale);
        }

        bool IsNearScale(double newScale)
        {
            double newScaleRatio = GeoScale/newScale;
            return (0.99 < newScaleRatio && newScaleRatio < 1.01);
        }

        public void ZoomIn()
        {
            SetScale(MapCoordinate.GeoScale/2.0);
        }

        public void ZoomOut()
        {
            SetScale(MapCoordinate.GeoScale*2.0);
        }

        public void ZoomByRatio(double zoomRatio)
        {
            _mouseControl.ZoomByRatio(zoomRatio);
        }

        public IPoint GetPixPointFromGeo(double lon, double lat)
        {
            return MapCoordinate.GetPixPointFromGeo(lon, lat);
        }

        public ILayer GetLayer(string name)
        {
            return LayerManager.GetLayer(name);
        }

        public void AddLayer(MapLayer layer)
        {
            if (! HasDataSourceInLayer(layer))
                return;

            layer.MapCoord = MapCoordinate;
            LayerManager.Add(layer);
            AddLayerPost(layer);
        }

        public void AddLayer(MapLayer layer, int position)
        {
            if (! HasDataSourceInLayer(layer))
                return;

            layer.MapCoord = MapCoordinate;
            LayerManager.Add(layer, position);
            AddLayerPost(layer);
        }

        public void AddLayerTop(MapLayer layer)
        {
            if (! HasDataSourceInLayer(layer))
                return;

            layer.MapCoord = MapCoordinate;
            LayerManager.AddTop(layer);
            AddLayerPost(layer);
        }

        public void AddLayerBottom(MapLayer layer)
        {
            if (! HasDataSourceInLayer(layer))
                return;

            layer.MapCoord = MapCoordinate;
            LayerManager.AddBottom(layer);
            AddLayerPost(layer);
        }

        protected void AddLayerPost(MapLayer layer)
        {
            layer.LabelLayer = _labelLayer;
            SetCopyright(layer);
            FireLayerAdded(layer);
        }

        public void RemoveLayer(MapLayer layer)
        {
            LayerManager.Remove(layer);
        }

        public void RemoveLayerAll()
        {
            LayerManager.RemoveAll();
        }

        // TODO: 
        public void Reload()
        {
            LayerManager.RemoveAllDrawings();
            //_mouseControl.Refresh();
            LayerManager.DrawAll();
        }

        private static bool HasDataSourceInLayer(MapLayer layer)
        {
            return (layer.MapSource != null);
        }

        private void CreateCopyrightStack()
        {
            _copyrightStack = new StackPanel();
            _copyrightStack.Orientation = Orientation.Vertical;
            _copyrightStack.SetValue(Canvas.LeftProperty, 4.0);
            _copyrightStack.SizeChanged += CopyrightStackSizeChanged;

            RootCanvas.Children.Add(_copyrightStack);
        }

        private void CopyrightStackSizeChanged(object sender, SizeChangedEventArgs e)
        {
            SetCopyrightStackTop();
        }

        private void SetCopyrightStackTop()
        {
            double canvasHeight = RootCanvas.ActualHeight;
            double stackHeight = _copyrightStack.ActualHeight;
            double topValue = canvasHeight - stackHeight - 4.0;

            _copyrightStack.SetValue(Canvas.TopProperty, topValue);
        }

        public void SetCopyright(MapLayer layer)
        {
            if (layer.CopyrightImage != null)
            {
                if (! _copyrightStack.Children.Contains(layer.CopyrightImage))
                {
                    _copyrightStack.Children.Add(layer.CopyrightImage);
                }
            }
            if (layer.Copyright != null)
            {
                if (!_copyrightStack.Children.Contains(layer.Copyright))
                {
                    _copyrightStack.Children.Add(layer.Copyright);
                }
            }
        }

        private void FireLayerAdded(ILayer mapLayer)
        {
            var e = new LayerAddedArgs(LayerManager.Layers, mapLayer);
            OnLayerAdded(e);
        }

        private void FireMapExtentChanged(IPolygon extent)
        {
            var e = new MapExtentChangedArgs(extent);
            LayerManager.DrawAll();
            OnMapExtentChanged(e);
        }

        private void FireMapScaleChanaged(double geoScale, double screenScale)
        {
            var e = new MapScaleChangedArgs(geoScale, screenScale);
            _mouseControl.CurrentScale = MapCoordinate.GeoScale;

            using (new MouseLock(_mouseControl))
            {
                LayerManager.RemoveAllDrawings();
                _labelLayer.Clear();
                LayerManager.DrawAll();
            }

            OnMapScaleChanged(e);
        }

        private void FireMouseMoved(IPoint geoPoint, Point mousePoint)
        {
            var e = new MouseMovedArgs(geoPoint, mousePoint);
            OnMouseMoved(e);
        }

        private void FireMouseClicked(IPoint geoPoint, Point mousePoint)
        {
            var e = new MouseClickedArgs(geoPoint, mousePoint);
            OnMouseClicked(e);
        }

        public void HideLabels()
        {
            _labelLayer.Visibility = Visibility.Collapsed;
        }

        public void ShowLabels()
        {
            _labelLayer.Visibility = Visibility.Visible;
        }

        public void Redraw()
        {
            if (MapCoordinate != null)
            {
                FireMapScaleChanaged(MapCoordinate.GeoScale, MapCoordinate.ScreenScale);
            }
        }
       
        private void ChangeProjectionBySrid(int orgSrid)
        {
            foreach( var layer in LayerManager.Layers )
            {
                layer.SetCoordTransformation();
            }

            var ct = TransformUtil.GetTransformation(orgSrid, Srid);
            var extent = TransformUtil.Transform(CurrentExtent, ct);

            double centerX = extent.Centroid.X;
            double centerY = extent.Centroid.Y;

            if (double.IsNaN(centerX)) centerX = 0;
            if (double.IsNaN(centerY)) centerY = 0;
            
            MoveTo(centerX, centerY, GeoScale);
            //MoveToExtents(extent);
        }


        #endregion

        #region handler

        //void rootCanvas_LayoutUpdated(object sender, EventArgs e)
        private void RootCanvasSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (RootCanvas == null)
            {
                return;
            }
            double w = RootCanvas.ActualWidth;
            double h = RootCanvas.ActualHeight;
            /*
            if (_layerContainer != null)
            {
                _layerContainer.Width = w;
                _layerContainer.Height = h;
            }
             */
            if (w == 0)
                return;
            if (h == 0)
                return;
            if (MapCoordinate != null)
            {
                MapCoordinate.SetScreenSize(w, h);
                FireMapScaleChanaged(MapCoordinate.GeoScale, MapCoordinate.ScreenScale);
            }
            SetClipOnRootCanvas(w, h);
            SetCopyrightStackTop();
        }

        private void MouseControlScreenScaleChanged(object sender, ScreenScaleChangedArgs e)
        {
            _mouseControl.IsLocked = true;
            MapCoordinate.AdjX = e.AdjX;
            MapCoordinate.AdjY = e.AdjY;

            double scale = MapCoordinate.ZoomByRatioAndAnchor(1/e.ScaleRatio, e.MoveX, e.MoveY);

            FireMapExtentChanged(MapCoordinate.CurrentExtent);
            FireMapScaleChanaged(MapCoordinate.GeoScale, MapCoordinate.ScreenScale);
            _mouseControl.IsLocked = false;
        }

        private void MouseControlContainerMoved(object sender, LayerContainerMovedArgs e)
        {
            _mouseControl.IsLocked = true;
            MapCoordinate.AdjX = e.AdjX;
            MapCoordinate.AdjY = e.AdjY;
            MapCoordinate.MoveByPixel(e.MoveX, e.MoveY);
            FireMapExtentChanged(MapCoordinate.CurrentExtent);
            _mouseControl.IsLocked = false;
        }

        public void ContainerLocationAdjust()
        {
            _mouseControl.IsLocked = true;
            double x, y;
            _mouseControl.GetAdjustXY(out x, out y);
            MapCoordinate.AdjX = x;
            MapCoordinate.AdjY = y;
            MapCoordinate.MoveByPixel(0, 0);
            FireMapExtentChanged(MapCoordinate.CurrentExtent);
            _mouseControl.IsLocked = false;
        }

        private void MouseControlMouseMoved(object sender, MouseMovedOnScreenArgs e)
        {
            IPoint geoPoint = MapCoordinate.GetGeoPointFromPixel(e.MouseX, e.MouseY);
            var mousePoint = new Point(e.MouseX, e.MouseY);
            FireMouseMoved(geoPoint, mousePoint);
        }

        private void mouseControl_MouseClickedOnScreen(object sender, MouseClickedOnScreenArgs e)
        {
            IPoint geoPoint = MapCoordinate.GetGeoPointFromPixel(e.MouseX, e.MouseY);
            var mousePoint = new Point(e.MouseX, e.MouseY);
            FireMouseClicked(geoPoint, mousePoint);
        }

        private void _mouseControl_MouseRangeBox(object sender, MouseRangeBoxArgs e)
        {
            IPoint start = MapCoordinate.GetGeoPointFromPixel(e.Start.X, e.Start.Y);
            IPoint end = MapCoordinate.GetGeoPointFromPixel(e.End.X, e.End.Y);

            double minX = Math.Min(start.X, end.X);
            double minY = Math.Min(start.Y, end.Y);
            double maxX = Math.Max(start.X, end.X);
            double maxY = Math.Max(start.Y, end.Y);

            if (e.Status == MouseRangeBoxStatus.SizeChanged)
            {
                LocalVectorLayer layer = LayerManager.RangeLayer;
                LocalVectorSource source = LayerManager.RangeSource;

                source.Clear();

                Geometry geom =
                    new Polygon(
                        new LinearRing(
                            new ICoordinate[]
                                {
                                    new Coordinate(minX, minY),
                                    new Coordinate(minX, maxY),
                                    new Coordinate(maxX, maxY),
                                    new Coordinate(maxX, minY),
                                    new Coordinate(minX, minY)
                                }
                            ));

                var data = new LocalVectorData();
                data.Geometry = geom;
                source.Add(data);
                layer.Clear();
                layer.Draw();
            }
            else if (e.Status == MouseRangeBoxStatus.Fixed || e.Status == MouseRangeBoxStatus.Cancel ||
                     e.Status == MouseRangeBoxStatus.Clear)
            {
                LocalVectorLayer layer = LayerManager.RangeLayer;
                LocalVectorSource source = LayerManager.RangeSource;
                source.Clear();
                layer.Clear();
                layer.Draw();
            }

            if (e.Status == MouseRangeBoxStatus.Fixed)
            {
                var args = new MouseRangeBoxFixedArgs();
                args.Start = start;
                args.End = end;
                OnMouseRangeBoxFixed(args);
            }
        }

        private void _mouseControl_MouseFeatureEdit(object sender, MouseFeatureEditArgs e)
        {
            IPoint point = MapCoordinate.GetGeoPointFromPixel(e.Point.X, e.Point.Y);

            EditVectorLayer layer = LayerManager.EditLayer;
            EditVectorSource source = LayerManager.EditSource;

            MouseFeatureEditStatus status = e.Status;

            if (status == MouseFeatureEditStatus.Click)
            {
                if (LayerManager.EditLayer.EditVectorMode != EditVectorMode.Edit)
                {
                    if (_hasArea)
                    {
                        ClearEditGeometry();
                        _hasArea = false;
                    }
                    source.AddPoint(point.X, point.Y);
                }

                source.SetWorkFeature();

                layer.Draw();

                // 矩形作成の場合は２点で確定にする
                if (MapMouseMode == MapMouseMode.CreateRectangle)
                {
                    if (source.Points.Count == 2)
                    {
                        status = MouseFeatureEditStatus.Fixed;
                    }
                }
                if (MapMouseMode == MapMouseMode.CreatePoint)
                {
                    status = MouseFeatureEditStatus.Fixed;
                }
            }

            else if (status == MouseFeatureEditStatus.Move)
            {
                if (_hasArea)
                {
                    return;
                }

                source.SetEditPoint(point.X, point.Y);

                source.SetWorkFeature();

                layer.Draw();
            }

            else if (status == MouseFeatureEditStatus.Cancel || e.Status == MouseFeatureEditStatus.Clear)
            {
                source.Clear();
                layer.Draw();
            }

            if (status == MouseFeatureEditStatus.Fixed)
            {
                if (MapMouseMode == MapMouseMode.CreatePoint)
                {
                    var args = new MouseFeatureEditFixedArgs();
                    args.Geometry = source.EditPoint.Geometry;
                    OnMouseFeatureEditFixed(args);
                }
                else
                {
                    source.EditPoint = null;
                    source.SetWorkFeature();
                    layer.EditVectorMode = EditVectorMode.NoEdit;
                    layer.Draw();

                    var args = new MouseFeatureEditFixedArgs();
                    args.Geometry = source.WorkGeometry;
                    OnMouseFeatureEditFixed(args);
                }

                _hasArea = true;
            }
        }

        private void _mouseControl_MouseFeatureDrag(object sender, MouseFeatureDragArgs e)
        {
            if (LayerManager.EditLayer.IsDrag)
            {
                if (e.MouseFeatureDragStatus == MouseFeatureDragStatus.Move)
                {
                    LayerManager.EditLayer.FeatureDrag(
                        new Point(e.MouseX, e.MouseY));
                }
                else if (e.MouseFeatureDragStatus == MouseFeatureDragStatus.Fixed)
                {
                    LayerManager.EditLayer.FeatureDragEnd(
                        new Point(e.MouseX, e.MouseY));
                }
            }
        }

        #endregion
    }
}